package com.vonchenchen.usbmuxd_android.usbmuxd.muxdprotocol.protocol;

import android.util.Log;

import com.vonchenchen.usbmuxd_android.usbmuxd.Config;


/**
 * usbmuxd相关结构
 * Created by lidechen on 2/25/17.
 */

public class ProtocolParser implements IProtocolParser{

    private final String TAG = "ProtocolParser";

    /**
     * 解析 MuxHeader
     * @param header
     * @param offset
     * @return
     */
    public UsbmuxdProtocol.MuxHeader parsePackageHeader(byte[] header, int offset){

        UsbmuxdProtocol.MuxHeader ret = new UsbmuxdProtocol.MuxHeader();

        ret.protocol = getInt(header, offset);
        ret.length = getInt(header, offset+1*4);

        if(Config.DEBUG) {
            Log.i(TAG, "protocol " + ret.protocol + "  length " + ret.length);
            //Log.i(TAG, Arrays.toString(header));
        }

        return ret;
    }

    /**
     * 返回Version信息
     * @return
     */
    public byte[] getVersionFeedbackData(){

        int len = UsbmuxdProtocol.MuxHeader.size + UsbmuxdProtocol.VersionHeader.size;
        byte[] ret = new byte[len];

        setInt(ret, 4*0, UsbmuxdProtocol.MUX_PROTO_VERSION);
        setInt(ret, 4*1, len);
        setInt(ret, 4*2, UsbmuxdProtocol.VERSION);
        setInt(ret, 4*3, 0);

        return ret;
    }

    /**
     * 解析tcp头
     * @param data
     * @param offset
     * @return
     */
    public UsbmuxdProtocol.TcpHeader parseTcpHeader(byte[] data, int offset){

        UsbmuxdProtocol.TcpHeader ret = new UsbmuxdProtocol.TcpHeader();

        ret.th_sport = getShort(data, offset);
        ret.th_dport = getShort(data, offset+2);

        ret.th_seq = getInt(data, offset+4);
        ret.th_ack = getInt(data, offset+8);

        ret.th_x2off = (char)data[offset+12];
        ret.th_flags = (char)data[offset+13];

        ret.th_win = getShort(data, offset+14);
        ret.th_sum = getShort(data, offset+16);
        ret.th_urp = getShort(data, offset+18);

        return ret;
    }

    /**
     * 将tcp头信息格式化,返回格式化buffer
     * @param th
     * @return
     */
    public byte[] getTcpHeader(UsbmuxdProtocol.TcpHeader th){

        byte[] ret = new byte[UsbmuxdProtocol.TcpHeader.size];

        setShort(ret, 0, th.th_sport);
        setShort(ret, 2, th.th_dport);
        setInt(ret, 4, th.th_seq);
        setInt(ret, 8, th.th_ack);

        ret[12] = 5;
        ret[13] = (byte) th.th_flags;

        setShort(ret, 14, th.th_win>>8);

        return ret;
    }

    /**
     * 将MuxHeader头信息格式化到指定buffer中
     * @param mem
     * @param offset
     * @param muxHeader
     */
    public void memsetMuxHeader(byte[] mem, int offset, UsbmuxdProtocol.MuxHeader muxHeader){

        setInt(mem, offset+0, muxHeader.protocol);
        setInt(mem, offset+1*4, muxHeader.length);
    }

    public void memsetVersionHeader(byte[] mem, int offset, UsbmuxdProtocol.VersionHeader versionHeader){

        setInt(mem, offset, versionHeader.major);
        setInt(mem, offset+4*1, versionHeader.minor);
        setInt(mem, offset+4*2, versionHeader.padding);
    }

    /**
     * 将tcp头信心格式化到指定buffer 中
     * @param mem
     * @param offset
     * @param th
     */
    public void memsetTcpHeader(byte[] mem, int offset, UsbmuxdProtocol.TcpHeader th){

        setShort(mem, offset+0, th.th_sport);
        setShort(mem, offset+2, th.th_dport);
        setInt(mem, offset+4, th.th_seq);
        setInt(mem, offset+8, th.th_ack);

        mem[offset+12] = 5;
        mem[offset+13] = (byte) th.th_flags;

        setShort(mem, offset+14, th.th_win);
    }

    //public void

    //小端
/*    private int getInt(byte[] data, int offset){

        int ret = 0;

        ret = ret | data[3+offset]<<24 | data[2+offset]<<16 | data[1+offset]<<8 | data[0+offset];
        return ret;
    }*/

    //大端
    private int getInt(byte[] data, int offset){

        int ret = 0;

        //ret = ret | data[3+offset] | data[2+offset]<<8 | data[1+offset]<<16 | data[0+offset]<<24;
        ret = ret | ((data[3+offset])&0x000000ff) | ((data[2+offset]<<8)&0x0000ff00) | ((data[1+offset]<<16)&0x00ff0000) | ((data[0+offset]<<24)&0xff000000);

        return ret;
    }

    private void setInt(byte[] data, int offset, int intData){

        data[offset] = (byte) (intData>>24 & 0x000000ff);
        data[offset+1] = (byte) (intData>>16 & 0x000000ff);
        data[offset+2] = (byte) (intData>>8 & 0x000000ff);
        data[offset+3] = (byte) (intData & 0x000000ff);
    }

    public static short getShort(byte[] data, int offset){

        int tmp = 0;

        tmp = tmp | data[offset+1] | data[offset]<<8;

        short ret = (short) tmp;
        return ret;
    }

    public static void setShort(byte[] data, int offset, int intData){

        data[offset] = (byte) (intData>>8 & 0x000000ff);
        data[offset+1] = (byte) (intData & 0x000000ff);
    }

    /*private long getLong(byte[] data, int offset){
        long ret = 0;

        ret = ret | data[7+offset]<<56 | data[6+offset]<<48 | data[5+offset]<<40 | data[4+offset]<<32 | data[3+offset]<<24 | data[2+offset]<<16 | data[1+offset]<<8 | data[0+offset];
        return ret;
    }*/

    public short htons(short x) { return Short.reverseBytes(x);   }
    public int   htonl(int x)   { return Integer.reverseBytes(x);    }

    @Override
    public void resetParser() {

    }
}
